#ifndef _MESHCOLOR_MODEL_
#define _MESHCOLOR_MODEL_

typedef math::vector<float, 3> Point ; 

GLfloat compute_k(Point p[3])
{
	float a = distance(p[1], p[2]) ;
	float b = distance(p[2], p[0]) ;
	float c = distance(p[0], p[1]) ;
	float k = (b*b + c * c - a * a) / (2.0 * c) ; 
	return GLfloat (k); 
}
GLfloat compute_h(Point p[3])
{
	float a = distance(p[1], p[2]) ;
	float b = distance(p[2], p[0]) ;
	float c = distance(p[0], p[1]) ;
	float cos_a = (b*b + c* c - a* a)/ (2.0 * b * c) ;
	float sin_a = sqrt (1.0 - cos_a * cos_a) ;
	return (b * sin_a) ;
}
GLfloat compute_c(Point p[3])
{
	return distance(p[0] , p[1]) ;
}


class Face 
{
public :
	typedef math::vector<float, 4> frgba_type ;
	Face (Texture & tm, unsigned _id, Point p[3], unsigned _mem) : 
	id(_id), ptm( & tm ), m_memid(_mem), m_res (2)
	{
		point[0] = p[0] ; point[1] = p[1] ; point[2] = p[2] ;
		compute_normalized_tex_param(); 
	}

	void write_tex_param ()
	{
		unsigned row = m_memid ;
		unsigned col = 0; 
		TexCoord texcoord ; 
		texcoord.x = col ;
		texcoord.y = row; 
		ptm->update (row, 0, frgba_type (m_res, 0.0f, 0.0f, 0.0f));

		if (k>=0)
		{
			ptm->update (row, 1, frgba_type (texcoord.x, texcoord.y, 0.0f, 0.0f));
			ptm->update (row, 2, frgba_type (texcoord.x + c, texcoord.y , 0.0f, 0.0f));
			ptm->update (row, 3, frgba_type (texcoord.x + k, texcoord.y + h, 0.0f, 0.0f));
		}
		else if (k < 0)
		{
			ptm->update(row, 1, frgba_type (texcoord.x - k, texcoord.y, 0.0f, 0.0f)); 
			ptm->update(row, 2, frgba_type (texcoord.x - k + c, texcoord.y, 0.0f, 0.0f )); 
			ptm->update(row, 3, frgba_type (texcoord.x, texcoord.y + h, 0.0f, 0.0f)); 
	
		}
		ptm->update (row, 4, frgba_type (1.0f, 0.0f, 0.0f, 1.0f));
		ptm->update (row, 5, frgba_type (0.0f, 1.0f, 0.0f, 1.0f));
		ptm->update (row, 6, frgba_type (0.0f, 0.0f, 1.0f, 1.0f));

		ptm->update (row, 7, frgba_type (1.0f, 1.0f, 0.0f, 1.0f));
		ptm->update (row, 8, frgba_type (0.0f, 1.0f, 1.0f, 1.0f));
		ptm->update (row, 9, frgba_type (1.0f, 0.0f, 1.0f, 1.0f));

		ptm->update (row, 10, frgba_type (1.0f, 0.0f, 0.0f, 1.0f));
		ptm->update (row, 11, frgba_type (0.0f, 0.5f, 0.0f, 1.0f));
		ptm->update (row, 12, frgba_type (0.0f, 0.0f, 0.5f, 1.0f));
		ptm->update (row, 13, frgba_type (1.0f, 0.0f, 0.5f, 1.0f));

	}
	void draw()
	{
		unsigned row = m_memid ;
		unsigned col = 0; 
		TexCoord texcoord ; 
		texcoord.x = col ;
		texcoord.y = row; 
	
		glBegin(GL_TRIANGLES);
		if (k >=0 )
		{
			glTexCoord2f(texcoord.x, 		texcoord.y); glVertex3f(point[0].x, point[0].y, point[0].z);
			glTexCoord2f(texcoord.x + c , 	texcoord.y ); glVertex3f(point[1].x, point[1].y, point[1].z);
			glTexCoord2f(texcoord.x + k , 	texcoord.y + h); glVertex3f(point[2].x, point[2].y, point[2].z);
		}
		else
		{
			glTexCoord2f(texcoord.x - k, 		texcoord.y); glVertex3f(point[0].x, point[0].y, point[0].z);
			glTexCoord2f(texcoord.x - k + c , 	texcoord.y ); glVertex3f(point[1].x, point[1].y, point[1].z);
			glTexCoord2f(texcoord.x , 	texcoord.y + h); glVertex3f(point[2].x, point[2].y, point[2].z);
		}
		glEnd();		
	}
private :
	void compute_normalized_tex_param ()
	{

		k = compute_k(point);
		h = compute_h(point);
		c = compute_c(point);
		if (h >=c) { k /= h ; c/=h ; h = 1.0f ; }
		else{ k /= c; h /= c; c = 1.0; }
		if (k < 0)
		{
			float ratio = c - k ;
			k /= ratio ; c /= ratio; h /= ratio ; 
		}
		if (k > 1.0)
		{
			float ratio = c + k ;
			k /= ratio ; c /=ratio ; h /=ratio ;
		}
	}
private:

	unsigned id ;
	unsigned m_memid ;
	float k, h, c ;
	Texture * ptm ;

	unsigned m_res; 
public :
	Point point[3];
};

#endif
